package com.ebupt.migu.music.commons.sms;

import com.alibaba.fastjson.JSONObject;
import com.ebupt.migu.common.sms.MegamarketRequestBean;
import com.ebupt.migu.common.util.DateUtil;
import com.ebupt.migu.common.util.HttpUtilsSMS;
import com.ebupt.migu.common.util.StrategyConstants;
import com.ebupt.migu.music.schedule.mapper.SMSTaskMapper;
import com.ebupt.migu.music.schedule.service.OfflineMessageProducerService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class Sender {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OfflineMessageProducerService service;

    @Autowired
    private SMSTaskMapper smsTaskMapper;

    @Value("${megamarket.ip}")
    private String MEGAMARKET_IP;

    @Value("${megamarket.sendMarketingSMS}")
    private String MEGAMARKET_SENDMARKETINGSMS;

    @Value("${megamarket.saltValue}")
    private String MEGAMARKET_SALTVALUE;

    @Value("${megamarket.sendChannel}")
    private String MEGAMARKET_SENDCHANNEL;

    @Value("${megamarket.accessCode}")
    private String MEGAMARKET_ACCESSCODE;

    /**
     * 登陆短信模板ID
     */
    public static String LOGIN_CODE = "20100001";

    /**
     * 短信接收成功
     */
    private static String MSG_RETURN_CODE_SUCCESS = "000000";
    private static String MSG_RETURN_CODE_FAIL = "000001";
    // 源号码(默认为10658830, 手机终端收到消息后显示的号码), 对于有扩展子号码的需求开放
    private static String SOURCE_ADDR = "10658830";

    private static String MEGAMARKET_RETURN_CODE_SUCCESS = "0";

    /**
     * MD5加密
     *
     * @param str 加密前的字符串
     * @return 返回加密后的字符串
     */
    private static String getMD5String(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5".toUpperCase());
            byte[] digest = md.digest(str.getBytes());
            return bytesToString(digest);
        } catch (Exception e) {
            log.error("md5加密失败，错误原因：[{}]", e.getMessage());
        }
        return null;
    }

    /**
     * 转换成String
     *
     * @param data byte数组
     * @return 转换后的string
     */
    private static String bytesToString(byte[] data) {
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        char[] temp = new char[data.length * 2];
        for (int i = 0; i < data.length; i++) {
            byte b = data[i];
            temp[(i * 2)] = hexDigits[(b >>> 4 & 0xF)];
            temp[(i * 2 + 1)] = hexDigits[(b & 0xF)];
        }
        return new String(temp).toUpperCase();
    }

    /**
     * 生成header 请求头（用于合法性验证）
     *
     * @return RequestHeader
     */
    private static RequestHeader getRequestHeader() {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String date = sdf.format(now);
        String msgId = "2010100" + date + "00000000";
        RequestHeader rh = new RequestHeader();
        rh.setMsgId(msgId);
        rh.setDeviceId("2010");
        rh.setDevicePwd(getMD5String(msgId + "123abc!@#"));
        rh.setAccessPlatformID("100");
        /**
         * 2023-06-18 业务说明：当前下发短信不需要再校验手机号是否属于移动手机号 参数说明【说明来自《短信模板消息下发接口规范》】： 1：需要状态报告(系统处理失败结果及手机终端回条)，0（及其他）：不需要, 默认为0
         * 因当前所下发通道无法获得上行信息，此参数留作备用，先全当0处理，功能待条件具备后实现；
         */
        rh.setNeedReport("1");
        return rh;
    }

    /**
     * 通用短信接口
     *
     * @param msgCode 短信模板ID,由消息下发平台统一配置分配
     * @param tel     目的手机号码,数组，可填多个
     * @param tplVars 模板中变量值(如模板中没有变量，可以为空)
     */
    public static boolean sendSMS(String msgCode, String[] tel, String[] tplVars) {
        Response response;
        log.info("短信模板[{}]，手机号码：[{}]，短信内容：[{}]", msgCode, tel, tplVars);
        try {
            response = new MessageSenderServiceLocator().getMessageSender().sendSmTplMessage(getRequestHeader(), SOURCE_ADDR, tel, msgCode, tplVars);
            log.info("response info:{}", response.toString());
            log.info("发送短信结果返回：code[{}], message[{}]", response.getReturnCode(), response.getDescription());
            if (response.getReturnCode().equals(MSG_RETURN_CODE_SUCCESS)) {
                return true;
            }
        } catch (Exception e) {
            log.error("短信发送失败，error[{}]", e.getMessage());
        }
        return false;
    }

    /**
     * 短信下发
     *
     * @param sid
     * @param msgCode
     * @param tel
     * @param tplVars
     * @return
     */
    @Async("strategy_executor")
    public void sendSMS(String sid, String msgCode, String[] tel, String[] tplVars, Map<String, Object> strategy) {
        Response response;
        log.info("短信模板[{}]，手机号码：[{}]，短信内容：[{}]", msgCode, tel, tplVars);
        // 短信发送进度
        String key_incr = sid + "_" + DateUtil.getDateToday() + "_incr";
        // 成功数
        String key_success = sid + "_" + DateUtil.getDateToday() + "_success";
        // 失败数
        String key_fail = sid + "_" + DateUtil.getDateToday() + "_fail";
        try {
            response = new MessageSenderServiceLocator().getMessageSender().sendSmTplMessage(getRequestHeader(), SOURCE_ADDR, tel, msgCode, tplVars);
            log.info("发送短信结果返回：手机号码:[{}], code[{}], message[{}]", tel, response.getReturnCode(), response.getDescription());
            redis_incr(key_incr);
            if (response.getReturnCode().equals(MSG_RETURN_CODE_SUCCESS)) {
                redis_incr(key_success);
                if (strategy.get("buriedType") != null && strategy.get("buriedType").toString().equals("1")) {
                    // 方舟埋点
                    insertArtGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_SUCCESS);
                } else if (strategy.get("buriedType") != null && strategy.get("buriedType").toString().equals("2")) {
                    // 流失客群埋点
                    insertLiushiGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_SUCCESS);
                }
            } else {
                redis_incr(key_fail);
                if (strategy.get("buriedType") != null && strategy.get("buriedType").toString().equals("1")) {
                    // 方舟埋点
                    insertArtGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_FAIL);
                } else if (strategy.get("buriedType") != null && strategy.get("buriedType").toString().equals("2")) {
                    // 流失客群埋点
                    insertLiushiGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_FAIL);
                }
            }
        } catch (Exception e) {
            log.error("短信发送失败，手机号码:[{}], error[{}]", tel, e.getMessage());
        }
    }

    /**
     * 原子自增
     *
     * @return
     */
    private void redis_incr(String key_name) {
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key_name, redisTemplate.getConnectionFactory());
        redisAtomicLong.getAndIncrement();
    }

    /**
     * 测试用例
     *
     * @return
     */
    public static Map<String, String> sendMsg() {
        Map<String, String> map = new HashMap<>();
        Response response;
        String[] tel = {"13688361924"};
        String[] tplVars = {"9527"};
        try {
            response = new MessageSenderServiceLocator().getMessageSender().sendSmTplMessage(getRequestHeader(), SOURCE_ADDR, tel, LOGIN_CODE, tplVars);
            map.put("code", response.getReturnCode());
            map.put("desc", response.getDescription());
            log.info("map info:{}", map.toString());
            if (!MSG_RETURN_CODE_SUCCESS.equals(response.getReturnCode())) {
                log.error("短信发送失败，错误代码：[{}],错误原因：[{}]", response.getReturnCode(), response.getDescription());
            }
        } catch (Exception e) {
            log.error("短信发送失败，error[{}]", e.getMessage());
        }
        return map;
    }

    /**
     * 短信下发
     *
     * @return
     */
    @Async("strategy_executor")
    public void testThread(int i, List<Integer> list) throws InterruptedException {
        System.out.println("开始执行线程" + i);
        TimeUnit.SECONDS.sleep(10);
        if (i % 2 == 0) {
            list.add(i);
        }
        System.out.println("结束执行线程" + i);
    }

    /**
     * 新增方舟客群明细记录，这里只记录成功和失败的明细信息
     *
     * @param strategy
     */
    private void insertArtGroupInfo(Map<String, Object> strategy, String phoneNo, String sendState) {
        smsTaskMapper.insertArkGroupInfo(strategy, phoneNo, sendState);
        log.info(">>>>>>>>>>>>>>新增短信下发的明细，号码{},成功标记{}", strategy.get("phoneNo"), sendState);
    }

    /**
     * 短信下发，适用于方舟埋点测试
     *
     * @param msgCode
     * @param tel
     * @return
     */
    @Async("strategy_executor")
    public void testSendSMS(String dateTime, String msgCode, String[] tel, boolean flag, Map<String, Object> strategy) {
        log.info("短信模板[{}]，手机号码：[{}]", msgCode, tel);

        try {
            if (flag) {
                insertArtGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_SUCCESS);
            } else {
                insertLiushiGroupInfo(strategy, tel[0], StrategyConstants.ARK_IMPORT_SEND_STATE_FAIL);
            }
        } catch (Exception e) {
            log.error("短信发送失败，手机号码:[{}], error[{}]", tel, e.getMessage());
        }
    }

    private void insertLiushiGroupInfo(Map<String, Object> strategy, String phoneNo, String sendState) {
        System.out.println("手机号码：" + phoneNo);
        smsTaskMapper.insertliushiInfo(strategy, phoneNo, sendState);
    }

    /**
     * 短信下发
     *
     * @param sid     策略id
     * @param tels    电话号码，多个,中间用,隔开
     * @param tplVars 内容
     * @return
     */
    @Async("strategy_executor")
    public void send2MegamarketSMS(String sid, String tels, String tplVars, Map<String, Object> strategy) {
        MegamarketRequestBean megamarket = new MegamarketRequestBean();
        megamarket.setMsisdn(tels);
        megamarket.setTemplateId(String.valueOf(strategy.get("templateId")));
        megamarket.setContent(tplVars);
        megamarket.setPort(Integer.parseInt(String.valueOf(strategy.get("smsSendPort"))));
        megamarket.setStrategyId(sid);
        megamarket.setExecuteType(Integer.parseInt(String.valueOf(strategy.get("executeType"))));
        service.offlineMessage(megamarket);
    }

    /**
     * 短信下发，用于测试
     *
     * @param sid     交易流水号，自己编，与大营销平台同步接口无关，只是用于下发后查日志
     * @param tels    电话号码，多个用,隔开
     * @param tplVars 短信内容
     * @return
     */
    @Async("strategy_executor")
    public String testsend2MegamarketSMS(String sid, String tels, String tplVars) {
        log.info("手机号码：[{}]，短信内容：[{}]", tels, tplVars);
        // 组装请求头
        Map<String, String> header = Maps.newHashMap();
        header.put("version", StrategyConstants.MEGAMARKET_VERSION);
        header.put("transactionId", sid);
        header.put("timestamp", DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS));
        header.put("accessCode", MEGAMARKET_ACCESSCODE);
        // 询问秘钥
        header.put("signature", getSignature(header));
        // 组装请求参数
        JSONObject body = new JSONObject();
        body.put("sendChannel", MEGAMARKET_SENDCHANNEL);
        body.put("sendType", StrategyConstants.MEGAMARKET_SENDTYPE_SMS);
        body.put("receiverNo", tels);
        body.put("msgType", StrategyConstants.MEGAMARKET_MSGTYPE);
        body.put("msgContent", tplVars);
        String url = MEGAMARKET_IP + MEGAMARKET_SENDMARKETINGSMS;
        JSONObject sendParams = new JSONObject();
        sendParams.put("body", body);
        sendParams.put("header", header);
        log.info(">>>>>>>>>>>>>>>请求报文:{}", sendParams.toJSONString());
        try {
            String responseString = HttpUtilsSMS.doPost(url, sendParams.toJSONString(), null);
            JSONObject response = JSONObject.parseObject(responseString);
            log.info("发送短信结果返回：手机号码:[{}], message[{}]", tels, response.toJSONString());
            if (response.getString("resultCode").equals("0")) {
                return "success";
            } else {
                return "fails";
            }
        } catch (Exception e) {
            log.error("短信发送失败，手机号码:[{}], error[{}]", tels, e.getMessage());
            return "error";
        }
    }

    /**
     * 拼接签名
     *
     * @param header
     * @return
     */
    private String getSignature(Map<String, String> header) {
        StringBuilder signature = new StringBuilder();
        signature.append("version").append("=").append(header.get("version")).append("&");
        signature.append("transactionId").append("=").append(header.get("transactionId")).append("&");
        signature.append("timestamp").append("=").append(header.get("timestamp")).append("&");
        signature.append("accessCode").append("=").append(header.get("accessCode"));
        signature.append(MEGAMARKET_SALTVALUE);
        return getMD5String(signature.toString()).toLowerCase();
    }

    // 拼接短信内容
    private String getMsgContent(String tplVars) throws UnsupportedEncodingException {
        JSONObject jsonObject = new JSONObject();
        final Base64.Encoder encoder = Base64.getEncoder();
        final byte[] textByte = tplVars.getBytes("UTF-8");
        final String encodedText = encoder.encodeToString(textByte);
        jsonObject.put("content", encodedText);
        jsonObject.put("contentType", StrategyConstants.MEGAMARKET_CONTENTTYPE_TEXT);
        return jsonObject.toJSONString();
    }


    public static void main(String[] args) {
        String msisdns = "13032567650,13083447221,13046390289,13006250008,13065042992,13096142093,13030355783,13060995095,13027529110,13026482177,13053238353,13024775888,13071373229,13056919851,13059483231,13086699658,13015455283,13094202606,13059660967,13089806062,13037421980,13026267029,13053143918,13027657250,13024428072,13089516062,13080016066,13055130513,13017090137,13049396842,13047045566,13013547081,13009151514,13098943538,13000384134,13057141642,13094994887,13087812132,13006206936,13077749708,13043657830,13082513040,13064228089,13084537833,13084098900,13010328572,13094732044,13019711686,13031839528,13039986098,13038939479,13082074668,13022308936,13052753838,13022804611,13086781074,13058075510,13059468635,13014471699,13026265458,13067743340,13017202777,13037287141,13025887039,13079947443,13000288578,13006724929,13002648214,13071307665,13044014973,13086548897,13030817098,13020572922,13080105753,13036782488,13068531390,13018228428,13046682675,13033784910,13050932583,13092371038,13012496431,13003444586,13023430068,13035967531,13058889196,13072708170,13069053700,13037253111,13014231769,13043988237,13097922398,13084257825,13040356294,13066685334,13000447486,13090371523,13038167536,13026724605,13088503018,13029565086,13068436493,13005330526,13086918480,13084635050,13077054968,13034392004,13029025170,13043369695,13088560538,13038210786,13045084062,13066090924,13002389473,13066885918,13078919731,13049754608,13013191925,13053902933,13055590403,13066284700,13016721176,13038833997,13098478647,13042717616,13029115243,13049899849,13043078408,13077609968,13070517815,13031212817,13007177257,13004439899,13004723835,13005865709,13062886623,13053890373,13002806076,13015570598,13048632961,13040093948,13020361475,13059166656,13092901407,13072496269,13045268759,13047153159,13020363401,13039202752,13078385749,13066891255,13088833342,13028512331,13009414233,13028927477,13071152323,13090315569,13074405801,13078430103,13007693047,13092685874,13055497110,13019880973,13097352357,13088198724,13028565747,13065224611,13027482823,13013879540,13095747533,13071538022,13065425597,13083802170,13048067873,13000776671,13032535947,13059073373,13048863880,13003260675,13009064154,13074467486,13053894831,13036131597,13073468273,13044746915,13081739762,13049389030,13096368925,13089899416,13048428931,13061105756,13039867903,13088899232,13086330704,13045167393,13042769574,13024492198,13037911577,13049784679,13018180599";
        System.out.println(msisdns.split(",").length);
    }
}
